package com.jweb.framework.http.support;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.util.WebUtils;
/**
 * 修改人： Thomas
 * 修改内容：新增 
 * 类说明： 对文件内容类型的处理
 */
public class MimeTypes {
	
	private static final Logger logger = LoggerFactory.getLogger(MimeTypes.class);
	private static final boolean b = ClassUtils.isPresent("javax.activation.FileTypeMap" , MimeTypesViewResolver.class.getClassLoader());
	
	private static final FileTypeMap fileTypeMap = getFileTypeMap();

	private boolean favorPathExtension = true ; 
	private boolean favorParameter = false ;
	private String parameterName = "format";
	
	private boolean ignoreAcceptHeader = false ;
	private MediaType defaultContentType ;
	private ConcurrentMap<String, MediaType> mediaTypes = new ConcurrentHashMap<String, MediaType>();
	
	
	private static FileTypeMap getFileTypeMap() {
		
		ClassPathResource classPathResource = new ClassPathResource("com/jkurrent/framework/http/support/mime-types.txt" , MimeTypes.class.getClassLoader());
		if(classPathResource.exists()){
			if(logger.isTraceEnabled()){
				logger.trace("Loading Java Activation Framework FileTypeMap from " + classPathResource);
			}
			InputStream is = null ;
			try {
				
				is = classPathResource.getInputStream();
				/*
				 * MimetypesFileTypeMap 此类扩展FileTypeMap 并通过其文件扩展名提供文件的数据分类。它使用 .mime.types格式。
				 */
				MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap(is);
				return mimetypesFileTypeMap ;
				
			} catch (Throwable t) {
				logger.warn("Loading FileTypeMap fail " , t);
			} finally {
				if(is != null){
					try {
						is.close();
					} catch (IOException e) {
						
					}
				}
			}
		}
		
		if(logger.isTraceEnabled()){
			logger.trace("Loading default Java Activation Framework FileTypeMap");
		}
		
		return FileTypeMap.getDefaultFileTypeMap();
	}
	
	public static MediaType getMediaType(String str){
		String localStr = fileTypeMap.getContentType(str);
		Object obj = ((StringUtils.hasText(localStr)) ? MediaType.parseMediaType(localStr) : null);
		
		return (MediaType) (MediaType.APPLICATION_OCTET_STREAM.equals(obj) ? null : obj) ;
	}
	
	public void setFavorPathExtension(boolean flag){
		this.favorPathExtension = flag ;
	}
	
	public void setFavorParameter(boolean flag){
		this.favorParameter = flag ;
	}
	
	public void setParameterName(String str){
		this.parameterName = str ;
	}
	
	public void setIgnoreAcceptHeader(boolean flag){
		this.ignoreAcceptHeader = flag ;
	}
	
	public void setDefaultContentType(String str){
		this.defaultContentType = MediaType.parseMediaType(str);
	}
	
	public void setMediaTypes(Map<String, String> map){
		Assert.notNull(map , "'mediaTypes' must not be null.");
		for(Map.Entry entry : map.entrySet()){
			String str = ((String)entry.getKey()).toLowerCase(Locale.ENGLISH);
			MediaType mediaType = MediaType.parseMediaType((String)entry.getValue());
			this.mediaTypes.put(str, mediaType);
		}
	}
	
	public List<MediaType> getMediaTypes(HttpServletRequest request){
		
		String str ; 
		Object obj ;
		if(this.favorPathExtension){ //true
			str = Utils.getPathHelper().getRequestUri(request); //"str"="/weather/Test.do"
			obj = WebUtils.extractFullFilenameFromUrlPath(str);// "obj"="Test.do"
			MediaType mediaType = getMediaTypeFromFilename((String)obj); // "mediaType"=MediaType {text/html} 
			
			if(mediaType != null){
				if(logger.isDebugEnabled()){
					logger.debug("Request media type is '" + mediaType +"' (based on filename '" + obj + "')");
				}
				return Collections.singletonList(mediaType);
			}
		}
		
		if((this.favorParameter) && request.getParameter(this.parameterName)!=null){
			str = request.getParameter(this.parameterName);
			obj = getMediaTypeFromExtension(str);
			if(obj != null){
				if(logger.isDebugEnabled()){
					logger.debug("Request media type is '" + obj + "' (based on parameter '" + this.parameterName + "'='" + str +"')");
				}
				return Collections.singletonList((MediaType)obj);
			}
		}
		
		if(!this.ignoreAcceptHeader){
			str = request.getHeader("Accept");
			if(StringUtils.hasText(str)){
				obj = MediaType.parseMediaTypes(str);
				MediaType.sortByQualityValue((List)obj);
				if(logger.isDebugEnabled()){
					logger.debug("Request media types are " + obj + " (based on Accept header)");
				}
				return (List<MediaType>) obj ;
			}
		}
		
		if(this.defaultContentType != null){
			if(logger.isDebugEnabled()){
				logger.debug("Request media types is " + this.defaultContentType +" (based on defaultContentType property)");
			}
			return Collections.singletonList(this.defaultContentType);
		}
		
		return Collections.emptyList();
	}

	private Object getMediaTypeFromExtension(String str) {
		
		return this.mediaTypes.get(str.toLowerCase(Locale.ENGLISH));
	}

	public MediaType getMediaTypeFromFilename(String paramStr) { // paramStr = Test.do
		
		String str = StringUtils.getFilenameExtension(paramStr); // str="do"
		if(!StringUtils.hasText(str)){
			return null; 
		}
		
		str = str.toLowerCase(Locale.ENGLISH); // str="do"
		MediaType mediaType = this.mediaTypes.get(str); // "mediaType"=MediaType {text/html}  
		if((mediaType == null) && this.b){ // false
			mediaType = getMediaType(paramStr);
			if(mediaType != null){
				this.mediaTypes.putIfAbsent(str, mediaType);
			}
		}
		
		return mediaType;
	}
	
}
